# 元组：既能像列表一样同时容纳多种不同类型的对象，也拥有字符串不可变的特性
# 列表：[元素1,元素2,...,元素N]
# 元组：(元素1,元素2,...,元素N）

rhyme = (1 ,2 ,3 , 4 ,5 , "上山打老虎")
print(rhyme) # (1, 2, 3, 4, 5, '上山打老虎')
# 其实，元组，可以不带括号
rhyme = 1 ,2 ,3 , 4 ,5 , "上山打老虎"
print(rhyme) # (1, 2, 3, 4, 5, '上山打老虎')

# 类似列表，元组也可以通过下标获取元素
print(rhyme[0]) # 1
print(rhyme[5]) # 上山打老虎
#。-1 ：最后一个元素
print(rhyme[-1]) # 上山打老虎

# 元组不可以修改
# rhyme[1] = 100 # TypeError: 'tuple' object does not support item assignment

# 切片：将目标对象中的元素以某种特定的组合导出，而不修改原来的对象
# 元组也可以切片
q_p = rhyme[:3]
print(q_p) # (1, 2, 3)
q_p = rhyme[3:]
print(q_p) # (4, 5, '上山打老虎')
q_p = rhyme[:]
print(q_p) #  (1, 2, 3, 4, 5, '上山打老虎')
q_p = rhyme[::2] # 跨度2
print(q_p) # (1, 3, 5)
q_p = rhyme[::-1] # 倒过来
print(q_p) # ('上山打老虎', 5, 4, 3, 2, 1)
# 原始的元组对象不变
print(rhyme) # (1, 2, 3, 4, 5, '上山打老虎')


nums = (3, 1, 9, 6, 8, 3, 5, 3)
# 统计 3 的次数
print(nums.count(3)) # 3 

heros = ("蜘蛛侠", "绿巨人", "黑寡妇")
# 查询 黑寡妇 的下标
print(heros.index("黑寡妇")) # 2

s = (1, 2, 3)
t = (4, 5, 6)
print(s + t) # (1, 2, 3, 4, 5, 6)
print(s * 3) # (1, 2, 3, 1, 2, 3, 1, 2, 3)

# 元组也可以嵌套
w = s, t
print(w) # ((1, 2, 3), (4, 5, 6))

# 元组可以迭代
for each in s :
    print(each) # 1 换行 2 换行 3

# 遍历嵌套元组 w
for i in w :
    for each in i:
        print(each)  # 1 换行 2 换行 3 换行 4 换行 5 换行 6

# 元组也支持列表推导式（列表推导式的结果为列表）
s = (1 ,2 ,3 , 4 ,5)
_ = [each * 2 for each in s]
print(_) # [2, 4, 6, 8, 10]

# 那么是否有元组推导式呢？
_ = (each * 2 for each in s)
print(_) # <generator object <genexpr> at 0x102766820>
# <generator object <genexpr> at 0x102766820> ? 这是什么呢？
# 反正得到的结果并不是元组，得到了一个叫做生成器的东西，其实，元组推导式并不存在

# 如何生成一个元素的元组？
x = (520)
# 使用函数 type(x) 来查看对象的类型
print(type(x)) # <class 'int'> 是一个数字
print(type(t)) # <class 'tuple'>

# 元素后加上逗号
x = (520,)
print(type(x)) #<class 'tuple'>


# 打包 和 解包
t = (123, "FishC", 3.14) # 定义元组的过程就是一个打包的过程，叫做打包
# 解包：将元组中的元素，一次性赋值给变量
x, y, z = t
print(x) # 123
print(y) # FishC
print(z) # 3.14

# 其实解包也适用于任何序列类型，比如说列表
t = [123, "FishC", 3.14]
x, y, z = t
print(x) # 123
print(y) # FishC
print(z) # 3.14

# 字符串也是一个序列类型，所以也可以进行解包操作
a, b, c, d, e = "FishC"
print(a) # F
print(b) # i
print(c) # s
print(d) # h
print(e) # C

# 解包的时候要注意：左边跟右边的数量一致，否则报错

# a, b, c, d, e, f= "FishC" # ValueError: not enough values to unpack (expected 6, got 5)
# a, b, c, d,= "FishC" # ValueError: too many values to unpack (expected 4)

# 除非这样,意思就是 第一个给a,第二个给b,后面的都给c
a, b, *c = "FishC"
print(a) # F
print(b) # i
print(c) # ['s', 'h', 'C']

# 多重赋值,其实他背后的实现逻辑就是先打包为元组，再解包赋值
x, y = 10, 20
print(x) # 10
print(y) # 20


# 元组真的 固若金汤 吗？
s = [1,2,3]
t = [4,5,6]
w = (s, t)
print(w) # ([1, 2, 3], [4, 5, 6])
# 但是，这个元组中的元素可以被修改
w[0][0] = 'a'
print(w) # (['a', 2, 3], [4, 5, 6])
# 这不就跟之前说的元组不可变相悖吗？
# 其实，元组本身是不可变的，但是，如果元组中的元素只是指向一个列表，我们是可以修改列表中的内容的